/*
 *  Copyright 2010 mazhao.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package shopping.model;

import org.apache.ibatis.session.SqlSession;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author mazhao
 */
public class Order extends OrderData {

    /**
     * Status transfer map
     * NEW     -> SENT     by Admin           when available
     * SENT    -> FINISHED by Customer        when received
     * NEW     -> CANCELED by Customer        when does not want it any more, before sent
     * NEW     -> PENDING  by Admin           when not available
     * PENDING -> CANCELED by Customer        when available
     * PENDING -> SENT     by Admin           when does not want it any more, before become available
     */
    public static final int ORDER_STATUS_ALL = 0;
    public static final int ORDER_STATUS_NEW = 10;
    public static final int ORDER_STATUS_SENT = 20;
    public static final int ORDER_STATUS_FINISHED = 30;
    public static final int ORDER_STATUS_PENDING = 40;
    public static final int ORDER_STATUS_CANCELED = 50;
    public static Map<Integer, String> status = new HashMap<Integer, String>();

    static {
        status.put(ORDER_STATUS_ALL, "");
        status.put(ORDER_STATUS_NEW, "New");
        status.put(ORDER_STATUS_SENT, "Sent");
        status.put(ORDER_STATUS_FINISHED, "Finished");
        status.put(ORDER_STATUS_PENDING, "Pending");
        status.put(ORDER_STATUS_CANCELED, "Canceled");

    }

    // ======================================================
    // static query section
    // ======================================================
    /**
     * select a specified user's orders.
     *
     * @param username
     * @return
     */
    public static List<Order> selectOrderByUser(String username) {
        String sqlKey = Order.class.getName() + ".selectOrderByUser";
        staticLog.debug("sql key " + sqlKey);

        SqlSession session = getSession();

        List<Order> orders = session.selectList(sqlKey, username);

        if (staticLog.isDebugEnabled()) {
            staticLog.debug("order item count " + orders.size());
            for (Order i : orders) {
                staticLog.debug(i);
            }
        }

        session.close();

        return orders;
    }

    public static List<Order> selectOrderByStatus(int status) {
        String sqlKey = Order.class.getName() + ".selectOrderByStatus";
        staticLog.debug("sql key " + sqlKey);

        SqlSession session = getSession();

        List<Order> orders = session.selectList(sqlKey, status);

        if (staticLog.isDebugEnabled()) {
            staticLog.debug("order item count " + orders.size());
            for (Order i : orders) {
                staticLog.debug(i);
            }
        }

        session.close();

        return orders;
    }

    public static List<Order> selectOrderByDateFromTo(Timestamp from, Timestamp to) {
        String sqlKey = Order.class.getName() + ".selectOrderByDateFromTo";
        staticLog.debug("sql key " + sqlKey);

        SqlSession session = getSession();

        Map paraMap = new HashMap<String, Timestamp>();
        paraMap.put("from", from);
        paraMap.put("to", to);

        List<Order> orders = session.selectList(sqlKey, paraMap);

        if (staticLog.isDebugEnabled()) {
            staticLog.debug("order item count " + orders.size());
            for (Order i : orders) {
                staticLog.debug(i);
            }
        }

        session.close();

        return orders;
    }

    // ===========================================
    // load order only, without order items
    // ===========================================
    /**
     * create new order <<without order items>>
     *
     * @return true for success, false else
     */
    public boolean insertOrder() {
        String sqlKey = getClassName() + "." + getCallerMethodName();
        log.debug("sql key " + sqlKey);

        if (autoTrans) {
            session = getSession();
        }

        int cnt = session.insert(sqlKey, this);
        log.debug("create new order " + cnt);
        if (autoTrans) {
            session.close();
        }
        return cnt > 0;
    }

    /**
     * create order items
     *
     * @param condition order items information (copy from product with these info)
     * @return
     */
    public boolean createOrderItem(Map condition) {
        String sqlKey = getClassName() + "." + getCallerMethodName();
        log.debug("sql key " + sqlKey);

        if (autoTrans) {
            session = getSession();
        }

        int cnt = session.update(sqlKey, condition);
        log.debug("created items count " + cnt);
        if (autoTrans) {
            session.close();
        }
        return cnt > 0;
    }

    /**
     * load order only without order item
     * @return true for success, false else
     */
    public boolean loadOrderOnly() {
        load();
        return true;
    }

    /**
     * @return
     */
    public List<OrderItem> getOrderItems() {
        String sqlKey = getClassName() + ".getOrderItems";
        log.debug("sql key for get order items is " + sqlKey);
        if (autoTrans) {
            session = getSession();
        }

        List<OrderItem> items = session.selectList(sqlKey, this);

        if (autoTrans) {
            session.close();
        }

        return items;
    }

    // ===========================================
    // status transfer methods
    // ===========================================
    private boolean updateStatus(int from, int to, String byWhom) {
        String sqlKey = getClassName() + ".updateStatus";
        String sqlKeyStatus = getClassName() + ".insertStatusLog";
        log.debug("sql key for update status is " + sqlKey);
        log.debug("update status from " + from + " to " + to);

        this.loadOrderOnly();
        log.debug("load original order successfully");

        if (this.getStatus() != from) {
            log.debug("from not equal, can not update");
            if (autoTrans) {
                session.close();
            }
            return false;
        }

        if (autoTrans) {
            session = getSession();
        }
        log.debug("begin update status");
        this.setStatus(to);
        try {
            recordCount = session.update(sqlKey, this);
            OrderStatusLog osl = new OrderStatusLog();
            osl.setOrderId(getId());
            osl.setStatusFrom(from);
            osl.setStatusTo(to);
            osl.setWho(byWhom);
            osl.setWhen(new Date());
            session.insert(sqlKeyStatus, osl);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        log.debug("update status successfully");

        log.debug("autoTrans:" + autoTrans);

        if (autoTrans) {
            log.debug("begin commit status chagne");
            session.commit();
            session.close();
        }

        return recordCount == 1;

    }

    public boolean newToSent(String byWhom) {
        return updateStatus(Order.ORDER_STATUS_NEW, Order.ORDER_STATUS_SENT, byWhom);
    }

    public boolean sentToFinished(String byWhom) {
        return updateStatus(Order.ORDER_STATUS_SENT, Order.ORDER_STATUS_FINISHED, byWhom);
    }

    public boolean newToCanceled(String byWhom) {
        return updateStatus(Order.ORDER_STATUS_NEW, Order.ORDER_STATUS_CANCELED, byWhom);
    }

    public boolean newToPending(String byWhom) {
        return updateStatus(Order.ORDER_STATUS_NEW, Order.ORDER_STATUS_PENDING, byWhom);
    }

    public boolean pendingToSent(String byWhom) {
        return updateStatus(Order.ORDER_STATUS_PENDING, Order.ORDER_STATUS_SENT, byWhom);
    }

    public boolean pendingToCanceled(String byWhom) {
        return updateStatus(Order.ORDER_STATUS_PENDING, Order.ORDER_STATUS_CANCELED, byWhom);
    }

    // ============================================
    // dynamic query {status, from, to}
    // ============================================
    public static List<Order> dynaQuery(Map param) {
        String sqlKey = Order.class.getName() + ".dynaQuery";
        staticLog.debug("dyna query sql:" + sqlKey);
        SqlSession session = getSession();

        List<Order> orders = session.selectList(sqlKey, param);
        session.close();
        return orders;
    }
}
